home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / rayshade / libray / libobj / cylinder.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  5KB  |  241 lines

  1. /*
  2.  * cylinder.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: cylinder.c,v 4.0 91/07/17 14:37:12 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    cylinder.c,v $
  19.  * Revision 4.0  91/07/17  14:37:12  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "geom.h"
  24. #include "cylinder.h"
  25.  
  26. static Methods *iCylinderMethods = NULL;
  27. static char cylName[] = "cylinder";
  28.  
  29. unsigned long CylTests, CylHits;
  30.  
  31. Cylinder *
  32. CylinderCreate(r, bot, top)
  33. Float r;
  34. Vector *bot, *top;
  35. {
  36.     Cylinder *cyl;
  37.     Float len;
  38.     Vector axis;
  39.  
  40.     if (r <= 0.) {
  41.         RLerror(RL_WARN, "Invalid cylinder radius.\n");
  42.         return (Cylinder*)NULL;
  43.     }
  44.  
  45.     VecSub(*top, *bot, &axis);
  46.  
  47.     len = VecNormalize(&axis);
  48.  
  49.     if (len < EPSILON) {
  50.         RLerror(RL_WARN, "Degenerate cylinder.\n");
  51.         return (Cylinder *)NULL;
  52.     }
  53.  
  54.     cyl = (Cylinder *)share_malloc(sizeof(Cylinder));
  55.     CoordSysTransform(bot, &axis, r, len, &cyl->trans);
  56.     return cyl;
  57. }
  58.  
  59. Methods *
  60. CylinderMethods()
  61. {
  62.     if (iCylinderMethods == (Methods *)NULL) {
  63.         iCylinderMethods = MethodsCreate();
  64.         iCylinderMethods->name = CylinderName;
  65.         iCylinderMethods->create = (GeomCreateFunc *)CylinderCreate;
  66.         iCylinderMethods->methods = CylinderMethods;
  67.         iCylinderMethods->intersect = CylinderIntersect;
  68.         iCylinderMethods->normal = CylinderNormal;
  69.         iCylinderMethods->uv = CylinderUV;
  70.         iCylinderMethods->bounds = CylinderBounds;
  71.         iCylinderMethods->stats = CylinderStats;
  72.         iCylinderMethods->checkbounds = TRUE;
  73.         iCylinderMethods->closed = FALSE;
  74.     }
  75.     return iCylinderMethods;
  76. }
  77.  
  78. /*
  79.  * Ray-cylinder intersection test.
  80.  */
  81. int
  82. CylinderIntersect(cyl, ray, mindist, maxdist)
  83. Cylinder *cyl;
  84. Ray *ray;
  85. Float mindist, *maxdist;
  86. {
  87.     Float t1, t2, a, b, c, zpos1, zpos2, disc;
  88.     Float distfact;
  89.     Ray newray;
  90.     Vector nray, npos;
  91.     Float nmin;
  92.  
  93.     CylTests++;
  94.  
  95.     /*
  96.      * Transform ray into canonical cylinder space.
  97.      */
  98.     newray = *ray;
  99.     distfact = RayTransform(&newray, &cyl->trans.itrans);
  100.     nray = newray.dir;
  101.     npos = newray.pos;
  102.     nmin = mindist * distfact;
  103.  
  104.     a = nray.x * nray.x + nray.y * nray.y;
  105.     if (a < EPSILON*EPSILON)
  106.         /* |nray.z| == 1. */
  107.         return FALSE;
  108.  
  109.     b = nray.x * npos.x + nray.y * npos.y;
  110.     c = npos.x*npos.x + npos.y*npos.y - 1;
  111.     disc = b*b - a*c;
  112.     if(disc < 0.)
  113.         return FALSE;
  114.     disc = sqrt(disc);
  115.     t1 = (-b + disc) / a;
  116.     t2 = (-b - disc) / a;
  117.     if (t1 < nmin && t2 < nmin)
  118.         return FALSE;
  119.     zpos1 = npos.z + t1 * nray.z;
  120.     zpos2 = npos.z + t2 * nray.z;
  121.  
  122.     if (t1 < nmin || zpos1 < 0. || zpos1 > 1.) {
  123.         if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
  124.             return FALSE;
  125.         else
  126.             t1 = t2 / distfact;
  127.  
  128.     } else {
  129.         if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
  130.             t1 /= distfact;
  131.         else {
  132.             t1 = min(t1, t2) / distfact;
  133.         }
  134.     }
  135.     
  136.     if (t1 < *maxdist) {
  137.         *maxdist = t1;
  138.         CylHits++;
  139.         return TRUE;
  140.     }
  141.     return FALSE;
  142. }
  143.  
  144. int
  145. CylinderNormal(cyl, pos, nrm, gnrm)
  146. Cylinder *cyl;
  147. Vector *pos, *nrm, *gnrm;
  148. {
  149.     /*
  150.      * Transform position into cylinder space.
  151.      */
  152.     *nrm = *pos;
  153.     PointTransform(nrm, &cyl->trans.itrans);
  154.     /*
  155.      * The normal is equal to the point of intersection in cylinder
  156.      * space, but with Z = 0.;
  157.      */
  158.     nrm->z = 0.;
  159.  
  160.     /*
  161.      * Tranform normal back to world space.
  162.      */
  163.     NormalTransform(nrm, &cyl->trans.itrans);
  164.     *gnrm = *nrm;
  165.     return FALSE;
  166. }
  167.  
  168. void
  169. CylinderUV(cyl, pos, norm, uv, dpdu, dpdv)
  170. Cylinder *cyl;
  171. Vector *pos, *norm, *dpdu, *dpdv;
  172. Vec2d *uv;
  173. {
  174.     Vector npos;
  175.  
  176.     npos = *pos;
  177.     PointTransform(&npos, &cyl->trans.itrans);
  178.  
  179.     uv->v = npos.z;
  180.     /*
  181.      * Due to roundoff error, |npos.x| may be > 1.
  182.      */
  183.     if (npos.x > 1.)
  184.         uv->u = 0.;
  185.     else if (npos.x < -1.)
  186.         uv->u = 0.5;
  187.     else
  188.         uv->u = acos(npos.x) / TWOPI;
  189.     if (npos.y < 0.)
  190.         uv->u = 1. - uv->u;
  191.  
  192.     if (dpdu) {
  193.         dpdv->x = dpdv->y = 0.;
  194.         dpdv->z = 1.;
  195.         dpdu->x = -npos.y;
  196.         dpdu->y = npos.x;
  197.         dpdu->z = 0.;
  198.         VecTransform(dpdu, &cyl->trans.trans);
  199.         VecTransform(dpdv, &cyl->trans.trans);
  200.         (void)VecNormalize(dpdu);
  201.         (void)VecNormalize(dpdv);
  202.     }
  203. }
  204.  
  205. void
  206. CylinderBounds(cyl, bounds)
  207. Cylinder *cyl;
  208. Float bounds[2][3];
  209. {
  210.     bounds[LOW][X] = bounds[LOW][Y] = -1;
  211.     bounds[HIGH][X] = bounds[HIGH][Y] = 1;
  212.     bounds[LOW][Z] = 0.;
  213.     bounds[HIGH][Z] = 1;
  214.     /*
  215.      * Transform bounding box to world space.
  216.      */
  217.     BoundsTransform(&cyl->trans.trans, bounds);
  218. }
  219.  
  220. char *
  221. CylinderName()
  222. {
  223.     return cylName;
  224. }
  225.  
  226. void
  227. CylinderStats(tests, hits)
  228. unsigned long *tests, *hits;
  229. {
  230.     *tests = CylTests;
  231.     *hits = CylHits;
  232. }
  233.  
  234. void
  235. CylinderMethodRegister(meth)
  236. UserMethodType meth;
  237. {
  238.     if (iCylinderMethods)
  239.         iCylinderMethods->user = meth;
  240. }
  241.